﻿using Google.Protobuf;
using HCService.MsgHandler;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HCService.Client
{
	public class ClientStream : IClient
	{

		public Socket ClientSocket { get; protected set; }
		public bool IsConnect { get; protected set; }

		Pack outPutPack = null;
		Pack interPack = null;
		NetworkStream clientStream;

		int packSizeIndex = 0;
		byte[] packSizeBuffer = new byte[sizeof(Int32)];

		SocketMsgCreater msgCache = new SocketMsgCreater(2048);

		public ClientStream(Socket socket)
		{
			this.ClientSocket = socket;
			outPutPack = null;
			interPack = null;
			clientStream = new NetworkStream(socket);
			IsConnect = true;
		}

		public bool IsClientReadable()
		{
			return null != this.ClientSocket && null != this.clientStream && this.ClientSocket.Connected && this.clientStream.CanRead;
		}

		public void DoUpdate()
		{
			if (!IsConnect) return;
			ListenClient();
		} 

		protected void ListenClient()
		{	
			//在客户端连接状态总是运行
			if (!IsClientReadable()) return;
			var stream = clientStream;
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         			try
			{
				//尝试取读取包
				outPutPack = null;
				//没有读取到 或者 读到的为空 则丢弃
				if (!GetPack(stream, out outPutPack) || outPutPack == null)
					return;

				MsgHandler.PackHandlerCenter.Instance.Handle_out(this, outPutPack);
			}
			catch (Exception exp)
			{
				Console.WriteLine($"客户端读取时发生异常 {exp.StackTrace}");
				this.Clear();
			}
			
		}

		protected bool GetPack(NetworkStream stream, out Pack pack) {

			pack = null;
			if(null == interPack)
			{
				if (!stream.DataAvailable || !stream.CanRead)
					return false;

				var count = stream.Read(packSizeBuffer, packSizeIndex, packSizeBuffer.Length - packSizeIndex);
				if (count <= 0)
				{
					Console.WriteLine("Client Read Null From Stream");
					throw new Exception("Client Read Null Form Stream");
				}
				packSizeIndex += count;

				if (packSizeIndex < sizeof(Int32))
					return false;

				int num = BitConverter.ToInt32(packSizeBuffer, 0);
				
				//从流数据中读取
				if (num == 0)
				{
					Console.WriteLine("Client Get An Empty Pack Length is 0");
					throw new Exception("Pack Length Zero");
				}
				//总长度减去包长信息
				interPack = new Pack(num - sizeof(Int32));
			}

			if (!stream.DataAvailable || !stream.CanRead)
				return false;
			//尝试读取满包
			var read = stream.Read(interPack.Buffer, interPack.CurIndex, interPack.ResumeSize);
			if(read <= 0)
			{
				Console.WriteLine("Client Read Null From Stream");
				throw new Exception("Client Read Null Form Stream");
			}
			interPack.CurIndex += read;
			if(interPack.ResumeSize == 0)
			{
				//读取一个完整包
				outPutPack = interPack;
				interPack = null;
				packSizeIndex = 0;
			}
			return true;
		}

		protected void Clear()
		{
			outPutPack = null;
			interPack = null;
			clientStream = null;
			packSizeIndex = 0;
		}

		public void DisConnect()
		{
			IsConnect = false;
		}

		public void Send(string handleTag, IMessage message)
		{
			if (IsConnect && IsClientReadable()) {
				byte[] hander = Encoding.UTF8.GetBytes(handleTag);
				var sizeh = hander.Length;
				byte[] content = message.ToByteArray();
				var sizec = content.Length;

				var totalLength = sizeh + sizec + 2 * sizeof(Int32);

				msgCache.Clear();
				msgCache.Write(totalLength);
				msgCache.Write(sizeh);
				msgCache.Write(hander);
				msgCache.Write(content);

				this.clientStream.Write(msgCache.Buffer, 0, msgCache.Position);
			}
		}
	}
}
